home *** CD-ROM | disk | FTP | other *** search
/ JCSM Shareware Collection 1993 November / JCSM Shareware Collection - 1993-11.iso / cl720 / mcomm55j.lzh / TXZM.C < prev    next >
C/C++ Source or Header  |  1993-03-14  |  50KB  |  1,417 lines

  1.  
  2. /*/////////////////////////////////////////////////////////////////////
  3. //                                                                   //
  4. //  TXZM.C -- zmodem protocol driver (formerly ZMP)                  //
  5. //                                                                   //
  6. //    (c) 1991,92, Mike Dumdei, 6 Holly Lane, Texarkana TX, 75503    //
  7. //                                                                   //
  8. //////////////////////////////////////////////////////////////////// */
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <stdarg.h>
  12. #include <string.h>
  13. #include <process.h>
  14. #include <ctype.h>
  15. #include <io.h>
  16. #include <dos.h>
  17. #include <bios.h>
  18. #include "comm.h"
  19. #include "ansidrv.h"
  20. #include "extra.h"
  21. #include "colors.h"
  22. #include "zmdos.h"
  23.  
  24. #if defined (__TURBOC__)
  25.   #include <dir.h>
  26.   #define ChDrive(d) setdisk((d)-1)
  27. #elif defined (__ZTC__)
  28.   #include <direct.h>
  29.   #define ChDrive(d) _chdrive(d)
  30. #elif defined (__MSC__)
  31.   int ndrives;
  32.   #define ChDrive(d) _dos_setdrive((d), &ndrives)
  33. #endif
  34.  
  35. #define ALT_C       0x2e00
  36. #define ALT_D       0x2000
  37. #define ALT_E       0x1200
  38. #define ALT_H       0x2300
  39. #define ALT_L       0x2600
  40. #define ALT_P       0x1900
  41. #define ALT_R       0x1300
  42. #define ALT_S       0x1f00
  43. #define ALT_X       0x2d00
  44. #define FK1         0x3b00
  45. #define PGUP        0x4900
  46. #define PGDN        0x5100
  47. #define ALT_EQU     0x8300
  48. #define X_ESC       0x011b
  49.  
  50. void AddToList(char *subdir);
  51. char *CaptureBaudRate(void);
  52. char *ConvertSecs(long secs);
  53. long ConvertTicks(long ticks);
  54. int Dial(void);
  55. void DrawBox(int row, int col, int nrows, int ncols, int color, int style);
  56. void DspZmodemScrn(void);
  57. char *ExpandSubDirs(char *fnames);
  58. int FileTransfer(void);
  59. void HelpFunc(void);
  60. void InitDefaults(void);
  61. void MiniTermMode(void);
  62. void ProcCmdLine(int argc, char * *argv);
  63. int prompt(char *buf, int maxlen);
  64. int RecurseSubDirs(char *sd);
  65. int RepeatDial(void);
  66. void SetFIFOLevels(int rxFIFOlevel, int txFIFOlevel);
  67. int SetParams(char *newparams);
  68. void usage(void);
  69. void vDisplay(int row, int col, char *format, ...);
  70. int waitfor(int ticks, ...);
  71. void ZMsg(int type, ...);
  72.  
  73. extern int  _C_ TestDesqView(void);
  74. extern int  _C_ DV_VideoSeg(int);
  75. extern void _C_ DV_TimeSlice(void);
  76.  
  77. /*/////////////////////////////////////////////////////////
  78. //  Configuration structure.  Structure is used to allow //
  79. //  the defaults to be changed modifying the EXE.        //
  80. //  "TXZMCFG:" is the tag to search for to find the start//
  81. //  of the structure in the EXE.                         //
  82. //////////////////////////////////////////////////////// */
  83. struct PROTCONFIG
  84. {
  85.     char    tag[8], DLPath[80], ULPath[80];
  86.     long    LocBaud, MinFifoBaud;
  87.     int     ComBase, IRQ, Vctr;
  88.     int     h_VBufSize, h_BufSize, b_VBufSize, b_BufSize;
  89.     int     TxWindow, ZExistOpts, XYExistOpts;
  90.     int     FifoTxLvl, FifoRxLvl;
  91.     char    IgnCarrier, MsrFlow, KeepTime, EscCtl, OvlyIO;
  92.     char    Color[10], Mono[10];
  93. } cfg =
  94. {
  95.     "TXZMCFG:", "", "",
  96.     0L, 1L,
  97.     0x3f8, IRQ4, VCTR4,
  98.     2048, 0, 20508, 20480,
  99.     0, 1, 2,
  100.     8, 8,
  101.     0, 0, 1, 0, 1,
  102.     {  WHT|BLU_B,  H_GRN|BLU_B,  H_RED|BLU_B,    YLW|BLU_B,
  103.        GRY|BLU_B,    YLW|BLU_B,  H_RED|BLU_B,  H_MAG|BLU_B,
  104.        CYN,              CYN_B  },
  105.     { WHT, WHT, RVRS, H_WHT, WHT, H_WHT, H_WHT, H_WHT, WHT, WHT_B }
  106. };
  107.  
  108. /*/////////////////////////////////////////////////////////
  109. //  Screen data structure                                //
  110. //////////////////////////////////////////////////////// */
  111. typedef struct
  112. {
  113.     int row, col, color, count;
  114.     char *text;
  115. } SCREENDATA;
  116.  
  117. /*/////////////////////////////////////////////////////////
  118. //  Global variables                                     //
  119. //////////////////////////////////////////////////////// */
  120. ASYNC port;                 /* ASYNC port structure */
  121. int combase, irq, vctr;     /* port address, IRQ number, & vector */
  122. int openmask = 0;           /* mask for forcing no FIFOs, no MSR intrpts */
  123. long LocBaud = 0L;          /* CPU to modem/device baud rate */
  124. char params[12] = "";       /* port parameters */
  125. char lockedbaud[12] = "";   /* locked baud parameter */
  126. char fnames[256] = "";      /* list of files to send if sending */
  127. char minsecs[10];           /* ticks to min:secs buffer */
  128. char *color;                /* pointer to list of colors */
  129. int txtcolor;               /* color of most screen message output */
  130. char buf[256];              /* general purpose buffer */
  131. int goodargs = 0;           /* got an 'r' or an 's' on command line */
  132. char *node = NULL;          /* for bbs use: LASTUSER.BBS format file name */
  133. int miniterm = 0;           /* mini-terminal mode selected */
  134. char OvlyIO;                /* overlay disk and serial I/O flag */
  135. char *flist;                /* used when expanding subdirectories */
  136. char mask[14];              /* used when expanding subdirectories */
  137. int plen;                   /* used when expanding subdirectories */
  138. int tryDV = 0;              /* cmdline switch to test for DesqView */
  139. int checkcarrier = 0;       /* check for carrier during 'waitfor' flag */
  140. int stripmask = 0xff;       /* strip high bit mask for miniterm mode */
  141. char phone[40] = "";        /* phone number to dial */
  142.  
  143. long tfBytes, tCPS;         /* total bytes transferred, average CPS */
  144. int tFiles;                 /* number of files transferred */
  145.  
  146. /*/////////////////////////////////////////////////////////
  147. //                                                       //
  148. //      Main                                             //
  149. //                                                       //
  150. //:mai////////////////////////////////////////////////// */
  151. void cdecl main(int argc, char *argv[])
  152. {
  153.     int i;
  154.  
  155.     color = ((initvid() & 0xff) == CO80) ? cfg.Color : cfg.Mono;
  156.     txtcolor = (int)color[1] & 0xff;
  157.     InitDefaults();
  158.     ProcCmdLine(argc, argv);
  159.     if (!goodargs)
  160.         usage();
  161.  
  162.     if (tryDV && TestDesqView() != 0)
  163.     {
  164.         i = DV_VideoSeg(v_seg);
  165.         if (v_seg != i)
  166.             v_seg = i, v_snow = 0;
  167.     }
  168.     if (*params)
  169.         ConnectBaud = atol(params);
  170.     if (*lockedbaud)
  171.         LocBaud = atol(lockedbaud);
  172.     if (LocBaud == 0L)
  173.         LocBaud = ConnectBaud;
  174.     if (LocBaud != 0L)
  175.     {
  176.         sprintf(params, "%ldN81", LocBaud);
  177.         if (LocBaud < cfg.MinFifoBaud)
  178.             openmask |= 0x4000;
  179.     }
  180.  
  181.     if (OvlyIO)
  182.         VBufSize = cfg.h_VBufSize, BufSize = cfg.h_BufSize;
  183.     else
  184.         VBufSize = cfg.b_VBufSize, BufSize = cfg.b_BufSize;
  185.     if (BufSize)
  186.         ZFR0 &= ~CANOVIO;
  187.  
  188.     AllocRingBuffer(&port, 2048, 4096, 0);
  189.     while (1)
  190.     {
  191.         i = async_open(&port, combase, irq, vctr|openmask, params);
  192.         if (i != 0)
  193.         {
  194.             printf("\nSerial port open error, Error code = %d\n\a", i);
  195.             exit(i - 20); /* -20 so exit code don't clash with zm result */
  196.         }
  197.         if (ConnectBaud == 0L)
  198.         {
  199.             ConnectBaud = atol(port.BPDSstr);
  200.             strcpy(params, port.BPDSstr);
  201.             if (ConnectBaud < cfg.MinFifoBaud && async_16550(&port)
  202.              && !(openmask & 0x4000))
  203.             {
  204.                 async_close(&port);
  205.                 openmask |= 0x4000;
  206.                 continue;
  207.             }
  208.         }
  209.         break;
  210.     }
  211.     async_msrflow(&port, cfg.MsrFlow);
  212.     tickhookset(1);
  213.  
  214.     if (miniterm)
  215.     {
  216.         pushscrn(0, 0, 25, 80);
  217.         SetFIFOLevels(1, 1);
  218.         MiniTermMode(), i = 0;
  219.         popscrn();
  220.     }
  221.     else
  222.     {
  223.         i = FileTransfer();
  224.         sprintf(buf, "TXZM exit code = %d", i);
  225.         v_color = WHT;
  226.         d_strat(23, 0, buf);
  227.     }
  228.     async_close(&port);
  229.     tickhookset(0);
  230.     exit(i);
  231. }
  232.  
  233. /*/////////////////////////////////////////////////////////
  234. //  AddToList                                            //
  235. //:add////////////////////////////////////////////////// */
  236. void AddToList(char *subdir)
  237. {
  238.     static char bkslsh[2] = " ";
  239.     int i, j;
  240.  
  241.     if (*(strchr(subdir, '\0') - 1) == '\\' || subdir == GetNameExt(subdir))
  242.         j = 1, *bkslsh = '\0';
  243.     else
  244.         j = 2, *bkslsh = '\\';
  245.     i = plen - 1;
  246.     plen += (strlen(subdir) + strlen(mask) + j);
  247.     flist = realloc(flist, plen);
  248.     sprintf(&flist[i], "\n%s%s%s", subdir, bkslsh, mask);
  249. }
  250.  
  251. /*/////////////////////////////////////////////////////////
  252. //  CaptureBaudRate                                      //
  253. //:cap////////////////////////////////////////////////// */
  254. char *CaptureBaudRate(void)
  255. {
  256.     int i;
  257.     static char *b[] = { "300", "300", "1200", "2400", "4800", "7200",
  258.         "9600", "14400", "19200" };
  259.  
  260.     checkcarrier = 0;
  261.     i = waitfor(18, "\r", b[1],b[2],b[3],b[4],b[5],b[6],b[7],b[8], NULL);
  262.     return ((i >= 0 && i <= 8) ? b[i] : NULL);
  263. }
  264.  
  265. /*///////////////////////////////////////////////
  266. //  ConvertSecs                                //
  267. //:con//////////////////////////////////////// */
  268. char *ConvertSecs(long secs)
  269. {
  270.     sprintf(minsecs, "%01ld:%02ld   " , uldiv(secs, 60L), ulmod(secs, 60L));
  271.     return(minsecs);
  272. }
  273.  
  274. /*///////////////////////////////////////////////
  275. //  ConvertTicks                               //
  276. //:con//////////////////////////////////////// */
  277. long ConvertTicks(long ticks)
  278. {
  279.     long secs = uldiv(ulmul(ticks, 10L), 182L) + 1L;
  280.     ConvertSecs(secs);
  281.     return(secs);
  282. }
  283.  
  284. /*/////////////////////////////////////////////////////////
  285. //  Dial                                                 //
  286. //:dia////////////////////////////////////////////////// */
  287. int Dial(void)
  288. {
  289.     int rval;
  290.     char *p1;
  291.  
  292.     async_txblk(&port, phone, strlen(phone));
  293.     checkcarrier = 0;
  294.     rval = waitfor(45 * 18, "CONNECT", "BUSY", "NO CARRIER", "VOICE",
  295.      "ERROR", "NO DIALTONE", NULL);
  296.     if (rval == 0)
  297.     {
  298.         if ((p1 = CaptureBaudRate()) != NULL)
  299.             SetParams(p1);
  300.     }
  301.     return (rval);
  302. }
  303.  
  304. /*/////////////////////////////////////////////////////////
  305. //  DrawBox                                              //
  306. //:dra////////////////////////////////////////////////// */
  307. void DrawBox(int row, int col, int nrows, int ncols, int color, int style)
  308. {
  309.     static char boxchars[][6] =
  310.     {
  311.         '┌', '┐', '└', '┘', '─', '│',
  312.         '╔', '╗', '╚', '╝', '═', '║',
  313.         '╒', '╕', '╘', '╛', '═', '│',
  314.         '╓', '╖', '╙', '╜', '─', '║'
  315.     };
  316.     char *box = boxchars[style];
  317.     int temp = v_color;
  318.  
  319.     v_color = color;
  320.     --ncols;
  321.     scrlupat(row, col, row + nrows - 1, col + ncols, nrows);
  322.     --nrows;
  323.     ++col, --ncols, --ncols;
  324.     d_nchat(row, col, box[4], color, ncols, 1);
  325.     d_nchat(row + nrows, col, box[4], color, ncols, 1);
  326.     d_nchat(row, col, box[5], color, nrows, 0);
  327.     d_nchat(row, col + ncols, box[5], color, nrows, 0);
  328.     d_chat(row, col, box[0]);
  329.     d_chat(row, col + ncols, box[1]);
  330.     d_chat(row + nrows, col, box[2]);
  331.     d_chat(row + nrows, col + ncols, box[3]);
  332.     v_color = temp;
  333. }
  334.  
  335. /*/////////////////////////////////////////////////////////
  336. //  DspZmodemScrn                                        //
  337. //:dsp////////////////////////////////////////////////// */
  338. void DspZmodemScrn(void)
  339. {
  340.     static SCREENDATA zscrn[] =
  341.     {
  342.         {  1,  6, 2,   0, " Zmodem File " },
  343.         {  2, 71, 0, -20, "│" },
  344.         { 15,  5, 0,  64, "─" },
  345.         {  2, 73, 0,   0, "F T" },
  346.         {  3, 73, 4, -19, "▒" },
  347.         {  3, 75, 4, -19, "▒" },
  348.         {  3,  5, 0,   0, "File name :" },
  349.         {  5,  5, 0,   0, "Estimated time :" },
  350.         {  6,  5, 0,   0, "Elapsed time   :" },
  351.         {  7,  5, 0,   0, "File CPS rate  :" },
  352.         {  5, 37, 0,   0, "File position      :" },
  353.         {  6, 37, 0,   0, "Expected file size :" },
  354.         {  7, 37, 0,   0, "Beginning offset   :" },
  355.         {  9, 51, 0,   0, "─── Hdr Data ───" },
  356.         { 10, 23, 0,   0, "Header Name" },
  357.         { 10, 40, 0,   0, "Type" },
  358.         { 10, 52, 0,   0, "Hex" },
  359.         { 10, 61, 0,   0, "Decimal" },
  360.         { 11,  5, 0,   0, "Last hdr recvd :" },
  361.         { 12,  5, 0,   0, "Last hdr sent  :" },
  362.         { 14,  5, 0,   0, "Crc :" },
  363.         { 14, 37, 0,   0, "Flow :" },
  364.         { 17,  5, 0,   0, "Total files queued :" },
  365.         { 18,  5, 0,   0, "Total bytes queued :" },
  366.         { 17, 42, 0,   0, "Estimated time   :" },
  367.         { 18, 42, 0,   0, "Accumulated time :" },
  368.         { 20,  5, 0,   0, "Files transferred  :" },
  369.         { 21,  5, 0,   0, "Bytes transferred  :" },
  370.         { 21, 42, 0,   0, "Average CPS rate :" },
  371.         { -1, -1, 0,   0, "" }
  372.     };
  373.     register SCREENDATA *sd;
  374.  
  375.     v_color = WHT;
  376.     cls();
  377.     v_color = txtcolor;
  378.     DrawBox(1, 1, 22, 78, color[0], 0);
  379.     for (sd = zscrn; sd->row >= 0; ++sd)
  380.     {
  381.         if (sd->count == 0)
  382.             d_msgat(sd->row, sd->col, color[sd->color], sd->text);
  383.         else if (sd->count > 0)
  384.         {
  385.             d_nchat(sd->row, sd->col, *sd->text, color[sd->color],
  386.              sd->count, 1);
  387.         }
  388.         else
  389.         {
  390.             d_nchat(sd->row, sd->col, *sd->text, color[sd->color],
  391.              -sd->count, 0);
  392.         }
  393.     }
  394.     d_msgat(1, 19, color[2], (TFlag.F.Receiving) ? "Receive " : "Send ");
  395.     loc(23, 0);
  396. }
  397.  
  398. /*/////////////////////////////////////////////////////////
  399. //  ExpandSubDirs                                        //
  400. //:exp////////////////////////////////////////////////// */
  401. char *ExpandSubDirs(char *fnames)
  402. {
  403.     DF fbuf;
  404.     char *p1, *lstptr, *wrkname, *savdir, *orgdir;
  405.     int i, dosub;
  406.  
  407.     orgdir = malloc(_MAX_PATH), getcwd(orgdir, _MAX_PATH);
  408.     wrkname = malloc(_MAX_PATH), savdir = malloc(_MAX_PATH);
  409.     plen = 1, lstptr = SkipSpaces(fnames), flist = calloc(1, 1);
  410.     while (1)
  411.     {
  412.         if (lstptr != fnames)
  413.         {
  414.             if (wrkname[1] == ':')
  415.                 chdir(savdir);
  416.             ChDrive(toupper(*orgdir) - 'A' + 1);
  417.             chdir(orgdir);
  418.         }
  419.         if (*lstptr == '\0')
  420.         {
  421.             free(wrkname), free(orgdir), free(savdir);
  422.             return(flist);
  423.         }
  424.         p1 = lstptr, i = SkipChars(lstptr) - lstptr, dosub = 0;
  425.         lstptr = (SkipSpaces(SkipChars(lstptr)));
  426.         if (*p1 == '(' && p1[i - 1] == ')')
  427.             ++p1, dosub = 2;
  428.         strncpy(wrkname, p1, i), wrkname[i - dosub] = '\0';
  429.         if (wrkname[1] == ':')
  430.         {
  431.             ChDrive(toupper(*wrkname) - 'A' + 1);
  432.             getcwd(savdir, _MAX_PATH);
  433.         }
  434.         p1 = GetNameExt(wrkname);
  435.         strcpy(mask, "*.*");
  436.         if (*p1)
  437.         {
  438.             fbuf.attrib = 0;
  439.             if (!strchr(p1, '*') && !strchr(p1, '?'))
  440.                 DosFindFirst(wrkname, -1, &fbuf);
  441.             if (fbuf.attrib & _A_SUBDIR)
  442.                 p1 = strchr(p1, '\0');
  443.             else
  444.             {
  445.                 strupr(strncpy(mask, p1, 12));
  446.                 p1[0] = mask[12] = '\0';
  447.             }
  448.         }
  449.         if (p1 != wrkname && *(--p1) != ':')
  450.         {
  451.             if (p1 != wrkname && *p1 == '\\' && *(p1 - 1) != ':')
  452.                 *p1 = '\0';
  453.             if (chdir(wrkname) != 0)
  454.                 continue;
  455.         }
  456.         getcwd(wrkname, _MAX_PATH);
  457.         if (dosub == 0)
  458.             AddToList(wrkname);
  459.         else
  460.             RecurseSubDirs(wrkname);
  461.     }
  462. }
  463.  
  464. /*/////////////////////////////////////////////////////////
  465. //  FileTransfer - file send / receive caller            //
  466. //:fil////////////////////////////////////////////////// */
  467. int FileTransfer(void)
  468. {
  469.     FILE *fh;
  470.     int rval, temp = v_color;
  471.     long efficiency = 0L;
  472.  
  473.     if (miniterm)
  474.         pushscrn(0, 0, 24, 80);
  475.     DspZmodemScrn();
  476.     if (node != NULL)           /* BBS support -- Maximus */
  477.     {
  478.         if ((fh = fopen(node, "rb")) != NULL)
  479.         {
  480.             memset(buf, 0, sizeof(buf));
  481.             fread(buf, 1, sizeof(buf), fh);
  482.             fclose(fh);
  483.             buf[32] = buf[68] = '\0';
  484.             d_msgat(23, 1, WHT, &buf[0]);
  485.             d_msgat(23, 40, WHT, &buf[36]);
  486.         }
  487.     }
  488.     SetFIFOLevels(cfg.FifoRxLvl, cfg.FifoTxLvl);
  489.     ZMsg(M_RESET);
  490.     if (TFlag.F.Receiving)
  491.         rval = ZmodemRecv(&port);
  492.     else
  493.     {
  494.         rval = ZmodemSend(&port, flist);
  495.         free(flist);
  496.     }
  497.     if (ConnectBaud)
  498.         efficiency = uldiv(ulmul(tCPS, 1000L), ConnectBaud);
  499.     sprintf(buf, "CPS: %ld (%d files, %ld bytes)  Efficiency %ld%% \r\n",
  500.      tCPS, tFiles, tfBytes, efficiency);
  501.     d_msgat(23, 1, WHT, buf);
  502.     tdelay(4);
  503.     if (node != NULL && async_carrier(&port) && tFiles)
  504.     {                           /* send other end result report */
  505.         async_txblk(&port, buf, strlen(buf));
  506.         while (!async_txempty(&port))
  507.             ;
  508.     }
  509.     async_rxflush(&port);
  510.  
  511.     v_color = temp;
  512.     if (miniterm)
  513.     {
  514.         SetFIFOLevels(1, 1);
  515.         d_str("  Press Enter to continue ..");
  516.         KBREAD;
  517.         popscrn();
  518.         d_str(buf);
  519.     }
  520.     return (rval);
  521. }
  522.  
  523. /*/////////////////////////////////////////////////////////
  524. //  HelpFunc - display help screen                       //
  525. //:hel////////////////////////////////////////////////// */
  526. void HelpFunc(void)
  527. {
  528.     static char helpscrn[] = "\n\
  529.     -- TXZM COMMANDS --\n\
  530.   ALT X:  Exit program         ALT E:  Echo On\n\
  531.   ALT S:  Shell to DOS         ALT P:  Change Baud\n\
  532.   ALT D:  Dial Number          ALT =:  Doorway Mode\n\
  533.   ALT R:  Redial Number        PGUP :  Send Zmodem\n\
  534.   ALT H:  Hang Up              PGDN :  Receive Zmodem\n\
  535.   ALT L:  Toggle Log File (TXZM.CAP)\n";
  536.  
  537.     d_str(helpscrn);
  538. }
  539.  
  540. /*/////////////////////////////////////////////////////////
  541. //  InitDefaults - init protocol global variables        //
  542. //:ini////////////////////////////////////////////////// */
  543. void InitDefaults(void)
  544. {
  545.     combase = cfg.ComBase, irq = cfg.IRQ, vctr = cfg.Vctr;
  546.     LocBaud = cfg.LocBaud;
  547.     OvlyIO = cfg.OvlyIO;
  548.     TFlag.F.ExistOpts = cfg.ZExistOpts;
  549.     TFlag.F.IgnCarrier = cfg.IgnCarrier;
  550.     TFlag.F.KeepTime = cfg.KeepTime;
  551.     TFlag.F.EscCtl = cfg.EscCtl;
  552.     TxWindow = cfg.TxWindow;
  553. }
  554.  
  555. /*/////////////////////////////////////////////////////////
  556. //  MiniTermMode - mini-terminal mode                    //
  557. //:min////////////////////////////////////////////////// */
  558. void MiniTermMode(void)
  559. {
  560.     static char rxtripstr[6] = { '*', '*', ZDLE, 'B', '0', '0' };
  561.     static FILE *flog = NULL;
  562.     int ch, rxtrip = 0, echo = 0, doorwaymode = 0;
  563.     char *cmd;
  564.     static char statline[] = "\
  565.  Help F1 | Exit ALT-X | Shell ALT-S | Hangup ALT-H | Send PGUP | Recv PGDN";
  566.  
  567.     cmd = getenv("COMSPEC");
  568.     if (cmd == NULL)
  569.         cmd = "COMMAND";
  570.     v_color = color[8];
  571.     cls();
  572.     sprintf(buf,
  573.      "TXZM 2.22 Mini-Terminal Mode : %s : (c) 1992 Mike Dumdei\n\n",
  574.      port.BPDSstr);
  575.     d_strat(1, 0, buf);
  576.     d_nchat(24, 0, ' ', color[9], 80, 1);
  577.     d_msgat(24, 1, color[9], statline);
  578.     SETWND(0, 0, 23, 79);
  579.     while (1)
  580.     {
  581.         if (KBHIT)
  582.         {
  583.             if ((unsigned)(ch = KBREAD) == ALT_EQU)
  584.             {
  585.                 if ((doorwaymode ^= 1) != 0)
  586.                 {
  587.                     v_btm = 24;
  588.                     d_nchat(24, 0, ' ', v_color, 80, 1);
  589.                 }
  590.                 else
  591.                 {
  592.                     if (((ch = getcurloc()) >> 8) == 24)
  593.                         d_ch('\n'), loc(23, (char)(ch & 0xff));
  594.                     v_btm = 23;
  595.                     d_nchat(24, 0, ' ', color[9], 80, 1);
  596.                     d_msgat(24, 1, color[9], statline);
  597.                 }
  598.             }
  599.             else if (doorwaymode)
  600.             {
  601.                 if (!(ch & 0xff))
  602.                 {
  603.                     async_tx(&port, '\0');
  604.                     ch >>= 8;
  605.                 }
  606.                 async_tx(&port, (char)ch);
  607.             }
  608.             else switch (ch)
  609.             {
  610.               case FK1:
  611.                 HelpFunc();
  612.                 break;
  613.               case ALT_C:
  614.                 v_color = 7;
  615.                 cls();
  616.                 break;
  617.               case ALT_X:
  618.                 return;
  619.               case ALT_H:
  620.                 async_dtr(&port, 0);
  621.                 tdelay(9);
  622.                 async_dtr(&port, 1);
  623.                 break;
  624.               case ALT_D:
  625.                 d_str("\nEnter number to dial (ESC to abort) :\n");
  626.                 if ((ch = prompt(buf, 32)) == 0)
  627.                     break;
  628.                 sprintf(phone, "ATDT%s\r", buf);
  629.                 Dial();
  630.                 break;
  631.               case ALT_R:
  632.                 if (*phone)
  633.                     RepeatDial();
  634.                 break;
  635.               case ALT_P:
  636.                 SetParams(NULL);
  637.                 break;
  638.               case ALT_L:
  639.                 if (flog)
  640.                 {
  641.                     fclose(flog);
  642.                     flog = NULL;
  643.                     d_str("\nTXZM.CAP file closed\n");
  644.                 }
  645.                 else
  646.                 {
  647.                     if ((flog = fopen("TXZM.CAP", "ab")) != NULL)
  648.                         d_str("\nTXZM.CAP file opened\n");
  649.                     else
  650.                         d_str("\nTXZM.CAP file open error\n");
  651.                 }
  652.                 break;
  653.               case ALT_E:
  654.                 echo ^= 1;
  655.                 break;
  656.               case ALT_S:
  657.                 pushscrn(0, 0, 25, 80);
  658.                 SETWND(0, 0, 24, 79);
  659.                 cls();
  660.                 d_str("Type EXIT and press ENTER to return to TXZM MiniTerm\n");
  661.                 spawnlp(P_WAIT, cmd, cmd, NULL);
  662.                 popscrn();
  663.                 SETWND(0, 0, 23, 79);
  664.                 break;
  665.               case PGUP:
  666.                 d_str("\nEnter filenames to send (ESC to abort) :\n");
  667.                 if ((ch = prompt(fnames, 255)) == 0)
  668.                     break;
  669.                 flist = ExpandSubDirs(fnames);
  670.                 TFlag.F.Receiving = 0;
  671.                 FileTransfer();
  672.                 break;
  673.               case PGDN:
  674.                 TFlag.F.Receiving = 1;
  675.                 FileTransfer();
  676.                 rxtrip = 0;
  677.                 break;
  678.               default:
  679.                 if (ch & 0xff)
  680.                 {
  681.                     async_tx(&port, (char)ch);
  682.                     if (echo)
  683.                     {
  684.                         d_ch((char)ch);
  685.                         if (flog)
  686.                             fputc(ch, flog);
  687.                     }
  688.                 }
  689.                 break;
  690.             }
  691.         }
  692.         else if (async_rxcnt(&port))
  693.         {
  694.             ch = async_rx(&port) & stripmask;
  695.             d_ch((char)ch);
  696.             if (ch != rxtripstr[rxtrip++])
  697.                 rxtrip = 0;
  698.             if (flog)
  699.                 fputc(ch, flog);
  700.             if (rxtrip == 6)
  701.             {
  702.                 TFlag.F.Receiving = 1;
  703.                 FileTransfer();
  704.                 rxtrip = 0;
  705.             }
  706.  
  707.         }
  708.         else if (tryDV)
  709.             DV_TimeSlice();
  710.     }
  711. }
  712.  
  713. /*/////////////////////////////////////////////////////////
  714. //  ProcCmdLine -- process commnad line args             //
  715. //:pro////////////////////////////////////////////////// */
  716. void ProcCmdLine(int argc, char *argv[])
  717. {
  718.                         /*   COM1   COM2   COM3   COM4  */
  719.     static int bases[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
  720.     static int irqs[4]  = {  IRQ4,  IRQ3,  IRQ4,  IRQ3 };
  721.     static int vctrs[4] = { VCTR4, VCTR3, VCTR4, VCTR3 };
  722.     FILE *fh;
  723.     int parg = 0, i, j;
  724.     char *p1;
  725.  
  726.     for (i = 1; i < argc; i++)
  727.     {
  728.         p1 = strupr(argv[i]);
  729.         if (*p1 == '-' || *p1 == '/')
  730.             ++p1;
  731.         if (parg == 0)
  732.         {
  733.             if (strncmp(argv[i], "COM", 3) == 0)
  734.             {
  735.                 j = atoi(isdigit(*(p1 += 3)) ? p1 : argv[++i]);
  736.                 if (j < 1 && j > 4)
  737.                     usage();
  738.                 --j, parg = 1;
  739.                 combase = bases[j], irq = irqs[j], vctr = vctrs[j];
  740.                 continue;
  741.             }
  742.         }
  743.         switch (*p1)
  744.         {
  745.           case 'C':             /* custom comm port */
  746.             if (!isxdigit(*++p1))
  747.                 p1 = argv[++i];
  748.             for (combase = 0; isxdigit(*p1); ++p1)
  749.             {
  750.                 combase = (combase << 4) | (*p1 - ((*p1 > '9' ) ?
  751.                  ('A' - 0xA) : '0'));
  752.             }
  753.             irq = atoi(&p1[1]);
  754.             if (irq < 2 || irq > 7 || parg)
  755.                 usage();
  756.             vctr = irq + 8;
  757.             irq = 1 << irq;
  758.             parg = 1;
  759.           case 'B':             /* connect baud rate */
  760.             strcpy(params, (isdigit(*++p1)) ? p1 : argv[++i]);
  761.             break;
  762.           case 'L':             /* locked baud rate */
  763.             strcpy(lockedbaud, (isdigit(*++p1)) ? p1 : argv[++i]);
  764.             break;
  765.           case 'D':             /* disable FIFOs */
  766.             openmask |= 0x4000;
  767.             break;
  768.           case 'M':             /* disable MSR interrupts */
  769.             openmask |= 0x2000;
  770.             break;
  771.           case 'H':             /* enable hardware handshake */
  772.             if (!isdigit(*++p1) || (j = atoi(p1)) < 0 || j > 3)
  773.                 j = 3;
  774.             if (j & 1)
  775.                 cfg.MsrFlow = B_CTS;    /* sender monitors CTS */
  776.             if (j & 2)
  777.                 cfg.MsrFlow |= B_RTS;   /* recvr drops RTS if rxbuf fills */
  778.             break;
  779.           case 'P':             /* send/accept complete pathnames */
  780.             TFlag.F.FullPath = 1;
  781.             break;
  782.           case 'I':             /* ignore loss of carrier */
  783.             TFlag.F.IgnCarrier = 1;
  784.             break;
  785.           case 'E':             /* option to take if file exists */
  786.             if (isdigit(*++p1) && (j = atoi(p1)) >= 0 && j <= 3)
  787.                 TFlag.F.ExistOpts = j;
  788.             break;
  789.           case 'X':             /* escape control characters */
  790.             if (!isdigit(*++p1) && !isdigit(*argv[i + 1]))
  791.                 TFlag.F.EscCtl = 1;
  792.             else
  793.             {
  794.                 if (!isdigit(*p1))
  795.                     p1 = argv[++i];
  796.                 do {
  797.                     j = atoi(p1);
  798.                     if ((j & 0xff60) == 0)
  799.                         ZTable[j] &= 0xf7;
  800.                     else if (j < 0 && (-j & 0xff60) == 0)
  801.                         ZTable[-j] |= 0x08;
  802.                     p1 = SkipSpaces(SkipChars(p1));
  803.                 } while (*p1);
  804.             }
  805.             break;
  806.           case 'V':             /* disable disk writes during serial I/O */
  807.             OvlyIO = 0;
  808.             break;
  809.           case 'W':             /* maximum tx bytes in transit */
  810.             TxWindow = atoi(isdigit(*++p1) ? p1 : argv[++i]);
  811.             break;
  812.           case 'N':             /* bbs use, node number follows */
  813.             node = (*++p1) ? p1 : argv[++i];
  814.             break;
  815.           case '6':             /* 16 bit CRCs only */
  816.             ZFR0 &= ~CANFC32;
  817.             break;
  818.           case '7':             /* strip high bit in mini-term mode */
  819.             stripmask = 0x7f;
  820.             break;
  821.           case '0':
  822.             v_bios = 1;         /* use bios for video */
  823.             break;
  824.           case 'Q':             /* test for DesqView environment */
  825.             tryDV = 1;
  826.             break;
  827.           case '!':  /* send hidden, keep file atrib, hide subs with FF or % */
  828.             TFlag.F.SendHid = TFlag.F.KeepAtrib = TFlag.F.HideSubs = 1;
  829.             break;
  830.           case 'U':             /* miniterm mode */
  831.             miniterm = goodargs = 1;
  832.             break;
  833.           case 'R':             /* receiving -- download path may follow */
  834.             TFlag.F.Receiving = 1;
  835.             if (*++p1 > ' ')
  836.                 DfltPath = p1;
  837.             else if (++i < argc)
  838.                 DfltPath = argv[i];
  839.             else
  840.                 DfltPath = cfg.DLPath;
  841.             i = argc;
  842.             ++goodargs;
  843.             break;
  844.           case 'S':             /* sending -- file names next args */
  845.             TFlag.F.Receiving = 0;
  846.             DfltPath = cfg.ULPath;
  847.             if (*++p1 > ' ')
  848.                 argv[i--] = p1;
  849.             if (*argv[i + 1] == '@')
  850.             {
  851.                 if ((fh = fopen(&argv[++i][1], "rb")) == NULL)
  852.                     break;
  853.                 j = (int)filelength(fileno(fh));
  854.                 if ((p1 = calloc(j + 1, 1)) == NULL)
  855.                 {
  856.                     fclose(fh);
  857.                     break;
  858.                 }
  859.                 fread(p1, 1, j, fh);
  860.                 fclose(fh);
  861.                 flist = ExpandSubDirs(p1);
  862.                 free(p1);
  863.                 i = argc;
  864.                 --goodargs;
  865.             }
  866.             else
  867.             {
  868.                 while (++i < argc)
  869.                 {
  870.                     strcat(fnames, " ");
  871.                     strcat(fnames, argv[i]);
  872.                     flist = ExpandSubDirs(fnames);
  873.                 }
  874.                 if (fnames[1])
  875.                     --goodargs;
  876.             }
  877.             break;
  878.         }
  879.     }
  880. }
  881.  
  882. /*/////////////////////////////////////////////////////////
  883. //  Prompt - prompt for input string                     //
  884. //:pro////////////////////////////////////////////////// */
  885. int prompt(char *buf, int maxlen)
  886. {
  887.     char *p1 = buf;
  888.     int ch = 0;
  889.  
  890.     while (ch != '\r' && ch != '\x1b')
  891.     {
  892.         if ((ch = (KBREAD & 0xff)) == '\r')
  893.             continue;
  894.         if (ch == '\b')
  895.         {
  896.             if (p1 > buf)
  897.                 d_ch((char)ch), --p1;
  898.         }
  899.         else if (p1 >= &buf[maxlen])
  900.             d_ch('\a');
  901.         else if (ch != '\x1b' && isprint(ch))
  902.             d_ch((char)ch), *p1++ = ch;
  903.     }
  904.     d_ch('\n');
  905.     if (ch == '\x1b')
  906.         p1 = buf;
  907.     *p1 = '\0';
  908.     return (*buf);
  909. }
  910.  
  911. /*/////////////////////////////////////////////////////////
  912. //  RecurseSubDirs                                       //
  913. //:rec////////////////////////////////////////////////// */
  914. int RecurseSubDirs(char *sd)
  915. {
  916.     DF fbuf;
  917.     static char subdir[_MAX_PATH];
  918.     int mask = (TFlag.F.SendHid) ? _A_SUBDIR|_A_HIDDEN : _A_SUBDIR;
  919.  
  920.     if (chdir(sd) != 0)
  921.         return 0;
  922.     getcwd(subdir, _MAX_PATH);
  923.     AddToList(subdir);
  924.     if (!DosFindFirst("*.*", mask, &fbuf))
  925.     {
  926.         do {
  927.             if (fbuf.attrib & _A_SUBDIR && fbuf.name[0] != '.')
  928.                 RecurseSubDirs(fbuf.name);
  929.         } while (!DosFindNext(&fbuf));
  930.     }
  931.     chdir("..");
  932.     return 1;
  933. }
  934.  
  935. /*/////////////////////////////////////////////////////////
  936. //  RepeatDial                                           //
  937. //:rep////////////////////////////////////////////////// */
  938. int RepeatDial(void)
  939. {
  940.     int rval, dials = 0, curpos = getcurloc();
  941.     char buf[40];
  942.  
  943.     while ((rval = Dial()) != 0 && rval != X_ESC)
  944.     {
  945.         tdelay(36);
  946.         while (async_rxcnt(&port))
  947.             d_ch((char)async_rx(&port));
  948.         sprintf(buf, "Dial Attempts = %d", ++dials);
  949.         d_str(buf);
  950.         setcurloc(curpos);
  951.     }
  952.     return (rval);
  953. }
  954.  
  955. /*/////////////////////////////////////////////////////////
  956. //  SetFIFOLevels - set FIFO levels                      //
  957. //:set////////////////////////////////////////////////// */
  958. void SetFIFOLevels(int rxFIFOlevel, int txFIFOlevel)
  959. {
  960.     if (port.Stat3 & B_FIFO)
  961.     {
  962.         async_FIFOrxlvl(&port, rxFIFOlevel);
  963.         async_FIFOtxlvl(&port, txFIFOlevel);
  964.     }
  965. }
  966.  
  967. /*/////////////////////////////////////////////////////////
  968. //  SetParams - set comport parameters                   //
  969. //:set////////////////////////////////////////////////// */
  970. int SetParams(char *newparams)
  971. {
  972.     if (newparams != NULL)
  973.         strcpy(buf, newparams);
  974.     else
  975.     {
  976.         d_str("\nEnter modem parameters (ESC to abort) :\n");
  977.         if (prompt(buf, 9) == 0)
  978.             return 0;
  979.     }
  980.     ConnectBaud = atol(buf);
  981.     if (*lockedbaud == '\0')
  982.     {
  983.         if (*(strrchr(buf, '0') + 1) == '\0')
  984.             strcat(buf, strrchr(params, '0') + 1);
  985.         strupr(buf);
  986.         if (async_setbpds(&port, buf) != 0) /* if no good */
  987.         {
  988.             ConnectBaud = atol(params);
  989.             return 0;
  990.         }
  991.         strcpy(params, buf);
  992.         LocBaud = ConnectBaud;
  993.     }
  994.     sprintf(buf,"\nModem Parameters: %s, ConnectBaud: %ld, LockedBaud: %ld\n",
  995.       port.BPDSstr, ConnectBaud, (*lockedbaud) ? LocBaud : 0L);
  996.     d_str(buf);
  997.     return 1;
  998. }
  999.  
  1000. /*///////////////////////////////////////////////
  1001. //  Usage                                      //
  1002. //:usa//////////////////////////////////////// */
  1003. void usage()
  1004. {
  1005.     static char msg1[] = "\n\
  1006. \
  1007. TXZM -- Zmodem Protocol Driver 2.22\n\
  1008.  (c) 1992, Mike Dumdei, 6 Holly Lane, Texarkana Tx 75503\n\
  1009. \n\
  1010. This program is a demo of the MCOMM5 'C' serial communications library.\n\
  1011. It may be used free of charge for non-commercial purposes.  It is not\n\
  1012. public domain and may not be modified, sold, or distributed for a fee\n\
  1013. with the exception of normal and reasonable shareware distribution fees.\n\
  1014. \n\
  1015. If you have a need for a C communications library, the latest shareware\n\
  1016. version of MCOMM5 (freq = MCOMM) is available from:\n\
  1017.   North East Texas DataLink BBS, Texarkana TX  (903) 838-6713  1:3819/128\n\
  1018. Features of MCOMM5 include:\n\
  1019.   Fully interrupt driven            16550 FIFO support\n\
  1020.   Up to 115200 baud                 Fast - 95%% ASM code\n\
  1021.   Library version: $25, Source included: $45\n\
  1022. \n\
  1023. << TXZM USAGE: >>\n\
  1024.   recv> txzm { port -b# -l# -t# -d -m -h -i -p -q -x -v -e# } -r {directory}\n\
  1025.   send> txzm { port -b# -l# -t# -d -m -h -i -p -q -x -w#    } -s file1 file2\n\
  1026.   term> txzm { port -b# -l# -t# -d -m -h -i -p -q -x -w# -v -e# } -u\n\
  1027. Arguments in braces are optional.  If a baud rate is not specified, the\n\
  1028. current baud rate will be used.  The -r or -s switches must come last\n\
  1029. on the command line.\n\
  1030. Press any key for command line switch descriptions.....";
  1031.  
  1032.     static char msg2[] = "\n\
  1033. \n\
  1034.  port : set to COM1 (default), COM2, COM3, COM4, or -c#,#\n\
  1035.          -c#,# : base port address of comm port in hex,IRQ (2-7)\n\
  1036.          Ex: -c2E8,5    Addrs=2E8 IRQ=5  (no spaces in arg)\n\
  1037.   -b# : baud rate -- if using a fixed DTE link, CONNECT baud rate\n\
  1038.   -l# : baud rate of fixed DTE link (locked baud rate)\n\
  1039.   -t# : maximum characters to send to 16550 FIFOs per interrupt\n\
  1040.          1-16, default is 8  (some modems may require lower setting)\n\
  1041.   -d  : if 16550 UART detected do not enable FIFOs, default is to enable\n\
  1042.   -m  : disable modem status register interrupts\n\
  1043.   -h  : use RTS/CTS hardware handshake\n\
  1044.   -i  : ignore absence of carrier detect\n\
  1045.   -p  : send/accept full pathnames (will create subdirs)\n\
  1046.   -q  : DesqView mode (use DV video buffer, timeslice when idle)\n\
  1047.   -x  : zdle escape all control characters, -x#,.. to esc particular chars\n\
  1048.   -v  : disable serial I/O during disk writes\n\
  1049.   -e# : duplicate file handling options (default = 1)\n\
  1050.          0=skip file, 1=resume transfer, 2=create dup name, 3=overwrite\n\
  1051.   -w# : transmit window size (must be multiple of 128)\n\
  1052.   -u  : start up in mini-terminal mode\n\
  1053.   -r  : receive,  directory is optional download directory\n\
  1054.   -s  : send, file names follow - recurses subdirs of names in parenthensis\n\
  1055. txzm com2 -b2400 -h -e2 -r   (COM2, 2400 baud, CTS hndshk, dup name if exist)\n\
  1056. txzm -l38400 -b9600 -s *.zip (38400 locked rate, 9600 CONNECT, send all ZIPs)\n\
  1057. txzm -p -s (c:\\subdir)       (send all files in all subdirs in c:\\subdir)";
  1058.  
  1059.     cls();
  1060.     printf(msg1);
  1061.     KBREAD;
  1062.     printf(msg2);
  1063.     exit(-100);
  1064. }
  1065.  
  1066. /*///////////////////////////////////////////////
  1067. //  vDisplay                                   //
  1068. //:vdi//////////////////////////////////////// */
  1069. void vDisplay(int row, int col, char *format, ...)
  1070. {
  1071.     va_list arg_ptr;
  1072.     char lbuf[80];
  1073.  
  1074.     va_start(arg_ptr, format);
  1075.     vsprintf(lbuf, format, arg_ptr);
  1076.     d_msgat(row, col, txtcolor, lbuf);
  1077. }
  1078.  
  1079. /* ////////////////////////////////////////////////////////////////
  1080. //  waitfor -  waits for one of a list of up to 10 different     //
  1081. //   strings to come in on the serial port.  The list must end   //
  1082. //   with NULL.  The ticks argument is how long to wait and is   //
  1083. //   in 1/18s of a second.  Calls MCOMM serial and timer LIB     //
  1084. //   functions.  Returns the index of the first targeted string  //
  1085. //   found or one of the above error values.                     //
  1086. //:wai////////////////////////////////////////////////////////// */
  1087. int waitfor(int ticks, ...)
  1088. {
  1089.     struct { int len; char *str; } list[11], *wp;
  1090.     va_list argptr;
  1091.     char ch, *p1, *buf;
  1092.     long to;
  1093.     int i, j, rxcnt = 0, longest = 0;
  1094.  
  1095.      /* load 'list' array with target strings and their lengths */
  1096.     va_start(argptr, ticks);
  1097.     for (i = 0, wp = list; i < 10; ++i, ++wp)
  1098.     {
  1099.         if ((wp->str = va_arg(argptr, char *)) == NULL)
  1100.             break;
  1101.         if ((wp->len = strlen(wp->str)) == 0)
  1102.             return (i);
  1103.         if (wp->len > longest)
  1104.             longest = wp->len;
  1105.     }
  1106.     wp->str = NULL;
  1107.  
  1108.      /* allocate buffer for incoming chars, start timer */
  1109.     p1 = buf = malloc(longest);   /* buf size is length of longest target */
  1110.     set_timeout(&to, ticks);
  1111.  
  1112.      /* wait for target string or error */
  1113.     while (1)
  1114.     {
  1115.         if (async_rxcnt(&port))         /* if character available */
  1116.         {
  1117.             ch = (char)async_rx(&port);
  1118.             d_ch(ch);
  1119.  
  1120.             if (rxcnt < longest)            /* if "incoming" buf not full */
  1121.             {                                       /* load ch in buf,  */
  1122.                 *p1 = ch;                           /* advance positon  */
  1123.                 if (++rxcnt < longest)
  1124.                     ++p1;
  1125.             }
  1126.             else                            /* if "incoming" buf is full */
  1127.             {                                       /* shuffle left 1 pos, */
  1128.                 memmove(buf, &buf[1], longest);     /* load ch in last pos */
  1129.                 *p1 = ch;
  1130.             }
  1131.             for (wp = list; wp->str; ++wp)  /* check for found target */
  1132.             {                               /* j selects pos in buf to look */
  1133.                 if ((j = rxcnt - wp->len) >= 0
  1134.                  && memicmp(wp->str, &buf[j], wp->len) == 0)
  1135.                 {
  1136.                     free(buf);
  1137.                     return (wp - list);     /* return index if found */
  1138.                 }
  1139.             }
  1140.         }
  1141.         else if (KBHIT && KBREAD == X_ESC)  /* check for local abort */
  1142.         {
  1143.             free(buf);
  1144.             return (X_ESC);
  1145.         }
  1146.         else if (timed_out(&to))            /* check for max time */
  1147.         {
  1148.             free(buf);
  1149.             return (TIMED_OUT);
  1150.         }                                   /* check for lost carrier */
  1151.         else if (checkcarrier && !async_carrier(&port)) /* see comment */
  1152.         {
  1153.             free(buf);
  1154.             return (LOST_CARRIER);
  1155.         }
  1156.     }
  1157. }
  1158.  
  1159. /*/////////////////////////////////////////////////////////
  1160. //  x_ansi -- handler for unrecognized ANSI sequences    //
  1161. //:x_a////////////////////////////////////////////////// */
  1162. void x_ansi(char *ansi_str)
  1163. {
  1164.     register char *p1 = strchr(ansi_str, '\0') - 1;
  1165.     WORD cp;
  1166.     char buf[15];
  1167.  
  1168.     if (*p1 == 'n')     /*  Device Status Report request */
  1169.     {
  1170.         if (*(--p1) == '6')
  1171.         {
  1172.             cp = getcurloc();
  1173.             sprintf(buf, "\x1b[%d;%dR", (cp >> 8) + 1, (cp & 0xff) + 1);
  1174.         }
  1175.         else if (*p1 == '5')
  1176.             strcpy(buf, "\x1b[0n");
  1177.         async_txblk(&port, buf, strlen(buf));
  1178.     }
  1179.     else                /*  unsupported, display in raw mode */
  1180.     {
  1181.         v_ansi = 0;
  1182.         d_str(ansi_str);
  1183.         v_ansi = 1;
  1184.     }
  1185. }
  1186.  
  1187. /*--------------------------------------------+
  1188. |  zmodem message types (defined in ZMDOS.H)  |
  1189. +---------------------------------------------/
  1190. #define M_RHDR      0       // received header
  1191. #define M_SHDR      1       // sent header
  1192. #define M_BLK0      2       // block 0 data processed (name, size, etc.)
  1193. #define M_CLASH     3       // file name clash occurred (use ExistOpts)
  1194. #define M_FILE      4       // start of transfer, FilePos = 1st position
  1195. #define M_EOF       5       // end of transfer (1 file)
  1196. #define M_DATA      6       // sent or received file data packet
  1197. #define M_FLOW      7       // change in XOFF or CTS flow status
  1198. #define M_IDLE      8       // waiting for character or for tx to empty
  1199. #define M_RESET     9       // reset to 'first file' condition */
  1200.  
  1201. /*/////////////////////////////////////////////////////////
  1202. //  ZMsg -- zmodem message handler                       //
  1203. //:zms///////////////////////////////////////////////:z: */
  1204. void ZMsg(int type, ...)
  1205. {
  1206.     static char *HdrType[] =
  1207.     {
  1208.         "Garbage Count", "Long Packet",   "Garbled Packet",   "Bad Crc",
  1209.         "Timed Out",     "Unknown Hdr",   "Sync Error",       "Memory Error",
  1210.         "File Error",    "Lost Carrier",  "Remote Abort",     "Local Abort",
  1211.         "ZRQINIT",       "ZRINIT",        "ZSINIT",           "ZACK",
  1212.         "ZFILE",         "ZSKIP",         "ZNAK",             "ZABORT",
  1213.         "ZFIN",          "ZRPOS",         "ZDATA",            "ZEOF",
  1214.         "ZFERR",         "ZCRC",          "ZCHALLENGE",       "ZCOMPL",
  1215.         "ZCAN",          "ZFREECNT",      "ZCOMMAND",         "ZSTDERR"
  1216.     };
  1217.     static char *HdrStyle[] = { "ZBIN", "ZHEX", "ZBIN32", "" };
  1218.     static char *CrcStyle[] = { "ZCRCE", "ZCRCG", "ZCRCQ", "ZCRCW" };
  1219.     static char MsgMask[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
  1220.  
  1221.     static long fStartTick, tStartTick, fCPS, fBytes, tBytes;
  1222.     static long fBarInc, tBarInc, fBarBytes, tBarBytes;
  1223.     static long fSize, fStartPos, updBytes, lastPos, orgTBytes;
  1224.     static long lastSec, lastTick, temp, flowhalts;
  1225.     static int tBarRow, fBarRow;
  1226.     static char gotBlock, crcType = ZCRCG, firstfile = 1;
  1227.  
  1228.     FILE *flog;
  1229.     va_list argptr;
  1230.     int i, j, row, hdr;
  1231.     long ticks;
  1232.     char *p1;
  1233.  
  1234.     if (MsgMask[type] == '\0')
  1235.         return;
  1236.     switch (type)
  1237.     {
  1238.       case M_RHDR:              /* received header */
  1239.       case M_SHDR:              /* sent header */
  1240.         row = (type == M_RHDR) ? 11 : 12;
  1241.         va_start(argptr, type);
  1242.         if ((hdr = va_arg(argptr, int)) < 0)
  1243.             ZHdr.Data = 0L;
  1244.         i = hdr + 12;
  1245.         j = va_arg(argptr, int) - 'A';
  1246.         if (j < 0 || j > 3)
  1247.             j = 3;
  1248.         vDisplay(row, 22, "%-17s%-9s%08lX%11ld", HdrType[i], HdrStyle[j],
  1249.          ZHdr.Data, ZHdr.Data);
  1250.         break;
  1251.       case M_CLASH:             /* file name clash occurred */
  1252.         if (TFlag.F.ExistOpts != 2)
  1253.             break;  /* not new name */
  1254.       case M_BLK0:              /* sent or received block 0 */
  1255.         i = sprintf(buf, "%-52s", PathName) - 52;
  1256.         d_msgat(3, 17, color[3], &(strupr(buf))[i]);
  1257.         if (type == M_CLASH)
  1258.             break;
  1259.         v_color = txtcolor;
  1260.         flowhalts = 0L;
  1261.         scrlupat(5, 22, 6, 32, 0);
  1262.         scrlupat(5, 58, 7, 68, 0);
  1263.         fSize = (TFlag.F.Receiving) ? RxdFileSize : FileSize;
  1264.         vDisplay(6, 58, "%-8ld", fSize);
  1265.         fStartTick = get_ticker();
  1266.         if (firstfile)
  1267.         {
  1268.             firstfile = tFiles = 0;
  1269.             tBytes = tBarBytes = 0L;
  1270.             lastSec = lastTick = tStartTick = fStartTick;
  1271.             tBarRow = 21;
  1272.             if ((tBarInc = uldiv(TotalBytes, 19L)) == 0)
  1273.                 ++tBarInc;
  1274.             orgTBytes = TotalBytes;
  1275.             tCPS = uldiv(ulmul(ConnectBaud, 955L), 10000L);
  1276.             if (tCPS == 0)
  1277.                 ++tCPS;
  1278.             vDisplay(17, 61, "%-8s",
  1279.              ConvertSecs(uldiv(TotalBytes, tCPS) + (TotalFiles >> 2)));
  1280.         }
  1281.         if ((fBarInc = uldiv(fSize, 19L)) == 0)
  1282.             ++fBarInc;
  1283.         fBarBytes = 0L, fBarRow = 21;
  1284.         d_nchat(3, 73, '▒', color[4], 19, 0);
  1285.         if (orgTBytes != 0L)
  1286.         {
  1287.             j = 3 + (int)((orgTBytes & 0xffff0000L) ?
  1288.              uldiv(TotalBytes, uldiv(orgTBytes, 19L)) :
  1289.              uldiv(ulmul(TotalBytes, 19L), orgTBytes));
  1290.             while (j < tBarRow && tBarRow > 2)
  1291.                 d_msgat(tBarRow--, 75, color[6], "▒");
  1292.             vDisplay(17, 26, "%-4d", TotalFiles - 1);
  1293.             vDisplay(18, 26, "%-8ld", TotalBytes - fSize);
  1294.         }
  1295.         else
  1296.         {
  1297.             tBarInc = fBarInc, tBarBytes = 0L, tBarRow = 21;
  1298.             d_nchat(3, 75, '▒', color[4], 19, 0);
  1299.         }
  1300.         break;
  1301.       case M_EOF:               /* end of file transfer */
  1302.         va_start(argptr, type);
  1303.         i = va_arg(argptr, int);
  1304.         if (i == ZEOF || i == ZRINIT)
  1305.         {
  1306.             vDisplay(20, 26, "%d", ++tFiles);
  1307.             tfBytes = tBytes;
  1308.             if (((p1 = getenv("TXZMLOG")) != NULL)
  1309.              && ((flog = fopen(p1, "at")) != NULL))
  1310.             {
  1311.                 sprintf(buf,
  1312.                  "%c %6ld %5ld bps %4ld cps %3u errors %5ld %4d %s %d\n",
  1313.                  TFlag.F.Receiving ? 'Z' : 'z', FilePos, ConnectBaud, fCPS,
  1314.                  ErrCnt, flowhalts, BlkLen, NameExt, (SerNbr) ? SerNbr : -1);
  1315.                 fputs(buf, flog);
  1316.                 fclose(flog);
  1317.             }
  1318.         }
  1319.         if (orgTBytes != 0L)
  1320.         {
  1321.             temp = TotalBytes - fSize;
  1322.             j = 3 + (int)((orgTBytes & 0xffff0000L) ?
  1323.              uldiv(temp, uldiv(orgTBytes, 19L)) :
  1324.              uldiv(ulmul(temp, 19L), orgTBytes));
  1325.             while (j < tBarRow && tBarRow > 2)
  1326.                 d_msgat(tBarRow--, 75, color[6], "▒");
  1327.         }
  1328.         crcType = ZCRCG;
  1329.         break;
  1330.       case M_FILE:              /* start of transfer, 1st FilePos set */
  1331.         lastPos = fStartPos = FilePos;
  1332.         fBytes = 0L;
  1333.         vDisplay(5, 22, "%-8s", ConvertSecs(uldiv(fSize - fStartPos, tCPS)));
  1334.         vDisplay(7, 58, "%-8ld", fStartPos);
  1335.         if (fStartPos == 0L)
  1336.             break;
  1337.         updBytes = fStartPos;
  1338.       case M_DATA:              /* sent or received file data packet */
  1339.         if (type != M_FILE)
  1340.         {
  1341.             gotBlock = 1;
  1342.             updBytes = FilePos - lastPos;
  1343.             lastPos = FilePos;
  1344.             fBytes += updBytes, tBytes += updBytes;
  1345.             vDisplay(5, 58, "%-8ld", FilePos);
  1346.             vDisplay(21, 26, "%-8ld", tBytes);
  1347.             va_start(argptr, type);
  1348.             vDisplay(14, 11, "%s-%s", (BinHdr == ZBIN32) ? "32" : "16",
  1349.              CrcStyle[(crcType = (char)va_arg(argptr, int)) - ZCRCE]);
  1350.         }
  1351.         fBarBytes += updBytes;
  1352.         tBarBytes += updBytes;
  1353.         while (fBarBytes >= fBarInc && fBarRow > 2)
  1354.             fBarBytes -= fBarInc, d_msgat(fBarRow--, 73, color[5], "▒");
  1355.         while (tBarBytes >= tBarInc && tBarRow > 2)
  1356.             tBarBytes -= tBarInc, d_msgat(tBarRow--, 75, color[6], "▒");
  1357.         break;
  1358.       case M_FLOW:
  1359.         va_start(argptr, type);
  1360.         switch (i = va_arg(argptr, int))
  1361.         {
  1362.           case 0:           /* XOFF cleared (XON received) */
  1363.           case 1:           /* XOFF received */
  1364.             d_msgat(14, 44, color[3], (i) ? "XOFF" : "    ");
  1365.             break;
  1366.           case 2:           /* CTS signal raised */
  1367.           case 3:           /* CTS signal lowered */
  1368.             d_msgat(14, 49, color[3], (i == 3) ? "CTS" : "   ");
  1369.             break;
  1370.           case 4:           /* port error */
  1371.             d_msgat(14, 55, color[3]|BLNK, "PORT RESET");
  1372.             tdelay(18);
  1373.             d_msgat(14, 55, color[3], "          ");
  1374.         }
  1375.         flowhalts += (i & 1);
  1376.         break;
  1377.       case M_IDLE:
  1378.         if (firstfile || (ticks = get_ticker()) == fStartTick)
  1379.             break;
  1380.         if (gotBlock || (crcType == ZCRCE && ticks != lastTick))
  1381.         {
  1382.             gotBlock = 0;
  1383.             lastTick = ticks;
  1384.             if (!(fBytes & 0xfff00000L))
  1385.                 fCPS = uldiv(uldiv(ulmul(fBytes,182L),ticks - fStartTick),10L);
  1386.             else
  1387.                 fCPS = uldiv(fBytes,uldiv(ulmul(ticks - fStartTick,10L),182L));
  1388.             if (!(tBytes & 0xfff00000L))
  1389.                 tCPS = uldiv(uldiv(ulmul(tBytes, 182L),ticks - tStartTick),10L);
  1390.             else
  1391.                 tCPS = uldiv(tBytes,uldiv(ulmul(ticks - tStartTick, 10L),182L));
  1392.             if (tCPS == 0)
  1393.                 ++tCPS;
  1394.             vDisplay(7, 22, "%-6ld", fCPS);
  1395.             vDisplay(21, 61, "%-6ld", tCPS);
  1396.         }
  1397.         if (ticks > (lastSec + 18))
  1398.         {
  1399.             lastSec = ticks;
  1400.             ConvertTicks(ticks - fStartTick);
  1401.             d_msgat(6, 22, txtcolor, minsecs);
  1402.             ConvertTicks(ticks - tStartTick);
  1403.             d_msgat(18, 61, txtcolor, minsecs);
  1404.         }
  1405.         if (tryDV)
  1406.             DV_TimeSlice();
  1407.         break;
  1408.       case M_RESET:
  1409.         if (cfg.MsrFlow && !async_cts(&port))
  1410.             d_msgat(14, 49, color[3], "CTS");
  1411.         crcType = ZCRCG, firstfile = 1;
  1412.         break;
  1413.     }
  1414. }
  1415.  
  1416.  
  1417.